package cn.wubo.task.order.statistics.service.impl;

import cn.wubo.task.order.statistics.entity.TaskOrderPersonDate;
import cn.wubo.task.order.statistics.mapper.TaskOrderPersonDateMapper;
import cn.wubo.task.order.statistics.record.PersonCalendarResultRecord;
import cn.wubo.task.order.statistics.service.ITaskOrderPersonDateService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.function.Function;

/**
 * <p>
 * 任务单工时 服务实现类
 * </p>
 *
 * @author baomidou
 * @since 2024-11-07
 */
@Service
public class TaskOrderPersonDateServiceImpl extends ServiceImpl<TaskOrderPersonDateMapper, TaskOrderPersonDate> implements ITaskOrderPersonDateService {

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean upload(String taskOrderId, Workbook wb) {
        Sheet sheet = wb.getSheet("人员工时详情");
        List<TaskOrderPersonDate> list = new ArrayList<>();
        for (int i = 1; i < sheet.getPhysicalNumberOfRows(); i++) {
            TaskOrderPersonDate taskOrderPersonDate = new TaskOrderPersonDate();
            taskOrderPersonDate.setTaskOrderId(taskOrderId);
            taskOrderPersonDate.setRank(sheet.getRow(i).getCell(0).getStringCellValue());
            taskOrderPersonDate.setPersonName(sheet.getRow(i).getCell(1).getStringCellValue());
            taskOrderPersonDate.setJob(sheet.getRow(i).getCell(2).getStringCellValue());
            taskOrderPersonDate.setAccount(sheet.getRow(i).getCell(3).getStringCellValue());
            taskOrderPersonDate.setDate(tranStringToLocalDate.apply(sheet.getRow(i).getCell(4).getStringCellValue()));
            taskOrderPersonDate.setDingdingcheckinduration(tranStringToBigDecimal.apply(sheet.getRow(i).getCell(5).getStringCellValue()));
            taskOrderPersonDate.setZentaoworkhours(tranStringToBigDecimal.apply(sheet.getRow(i).getCell(6).getStringCellValue()));
            taskOrderPersonDate.setPendingconfirmationhours(tranStringToBigDecimal.apply(sheet.getRow(i).getCell(7).getStringCellValue()));
            taskOrderPersonDate.setReducedhours(tranStringToBigDecimal.apply(sheet.getRow(i).getCell(8).getStringCellValue()));
            taskOrderPersonDate.setAcceptedhours(tranStringToBigDecimal.apply(sheet.getRow(i).getCell(9).getStringCellValue()));
            taskOrderPersonDate.setReductionreason(sheet.getRow(i).getCell(10).getStringCellValue());
            list.add(taskOrderPersonDate);
        }

        this.removeByTaskOrderId(taskOrderId);
        return this.saveBatch(list);
    }

    @Override
    public Boolean removeByTaskOrderId(String taskOrderId) {
        return this.remove(this.lambdaQuery().eq(TaskOrderPersonDate::getTaskOrderId, taskOrderId).getWrapper());
    }

    @Override
    public PersonCalendarResultRecord searchPersonCalendar(String year, List<String> personNames) {
        List<TaskOrderPersonDate> taskOrderPersonDateList = this.lambdaQuery().list();

        LocalDate startDate = LocalDate.of(Integer.parseInt(year), 1, 1);
        LocalDate endDate = startDate.with(TemporalAdjusters.lastDayOfYear()); // 当年的最后一天

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        List<String> calendar = new ArrayList<>();
        for (LocalDate date = startDate; !date.isAfter(endDate); date = date.plusDays(1)) {
            String str = date.format(formatter);
            calendar.add(str);
        }

        List<Map<String, String>> data = new ArrayList<>();
        List<Map<String, Object>> hour = new ArrayList<>();
        for (String personName : personNames) {
            Map<String, String> dataRowMap = new HashMap<>();
            Map<String, Object> hourRowMap = new HashMap<>();
            dataRowMap.put("personName", personName);
            hourRowMap.put("personName", personName);

            for (String date : calendar) {
                Optional<TaskOrderPersonDate> opt = taskOrderPersonDateList.stream().filter(t -> t.getPersonName().equals(personName) && t.getDate().format(formatter).equals(date)).findAny();
                if (opt.isPresent()) {
                    dataRowMap.put(date, "1");
                    TaskOrderPersonDate taskOrderPersonDate = opt.get();
                    hourRowMap.put(date, getHourOfDate.apply(taskOrderPersonDate));
                } else {
                    dataRowMap.put(date, "");
                    hourRowMap.put(date, BigDecimal.ZERO);
                }
            }

            data.add(dataRowMap);
            hour.add(hourRowMap);
        }
        return new PersonCalendarResultRecord(calendar, data, hour);
    }

    @Override
    public PersonCalendarResultRecord searchPersonMonth(String year, List<String> personNames) {
        List<TaskOrderPersonDate> taskOrderPersonDateList = this.lambdaQuery().list();

        List<String> monthList = Arrays.asList("01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12");

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");

        List<Map<String, Object>> data = new ArrayList<>();
        for (String personName : personNames) {
            Map<String, Object> dataRowMap = new HashMap<>();
            dataRowMap.put("personName", personName);

            for (String month : monthList) {
                // @formatter:off
                BigDecimal num = taskOrderPersonDateList
                        .stream()
                        .filter(t -> t.getPersonName().equals(personName) && t.getDate().format(formatter).equals(year + "-" + month))
                        .map(getHourOfDate)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                // @formatter:on
                dataRowMap.put(month, num);
            }

            data.add(dataRowMap);
        }
        return new PersonCalendarResultRecord(monthList, null, data);
    }

    private final Function<String, LocalDate> tranStringToLocalDate = value -> {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        try {
            ZonedDateTime zonedDateTime = simpleDateFormat.parse(value).toInstant().atZone(ZoneId.systemDefault());
            return zonedDateTime.toLocalDate();
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    };

    private final Function<String, BigDecimal> tranStringToBigDecimal = value -> StringUtils.hasText(value) ? new BigDecimal(value) : null;

    private final Function<TaskOrderPersonDate, BigDecimal> getHourOfDate = value -> {
        if (value.getAcceptedhours() != null) {
            return value.getAcceptedhours();
        } else if (value.getDingdingcheckinduration() != null) {
            return value.getDingdingcheckinduration().min(value.getZentaoworkhours());
        } else {
            return value.getZentaoworkhours();
        }
    };
}
